//
//  DBParser.m
//  parser
//
//  Created by Daniel Braun on 04/05/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "DBLexer.h"
#import "DBParser.h"
#import "DBParserAstNode.h"
#import "StringExtension.h"

@implementation DBParser
- (id) init {
	self = [super init];
	if (self != nil) {
		nodeClass=[DBParserAstNode class];
		nodeStack=[[NSMutableArray arrayWithCapacity:10]retain];
	}
	return self;
}

- (void) dealloc {
	[rule release];
	[tokens release];
	[target release];
	[curNode release];
	[nodeStack release];
	[super dealloc];
}

- (void) setRule:(DBParserRule *) r
{
	if (r==rule) return;
	[rule release];
	rule=[[r instantiateRule] retain];
	[rule preProcess];
}

- (void) parseTokens:(NSArray *) tok
{
	NSLog(@"handling tokens %@", tok);
	[tokens release];
	tokens=[tok retain];
	tindex=0;
	tnum=[tokens count];
	[rule invokeWithParser:self];
}

/* called by rules */
- (DBLexerTokenMatch *) _lookAhead0
{
	return [self _lookAhead:0];
}
- (DBLexerTokenMatch *) _lookAhead:(int)k
{
	int i;
	i=tindex+k;
	if (i<tnum) return [tokens objectAtIndex:i];
	return [DBLexerTokenMatch eofToken];
}
- (int) _tlookAhead0
{
	return [self _tlookAhead:0];
}
- (int) _tlookAhead:(int)k
{
	int i;
	i=tindex+k;
	int t;
	if (i<tnum) {
		t=[[tokens objectAtIndex:i]tokval];
	} else {
		t=[[DBLexerTokenMatch eofToken]tokval];
	}
	NSLog(@"\t\tlookahead(%d)=%d\n",k,t);
	
	return t;
}
- (void) _consume
{
	if (1) {
		DBLexerTokenMatch *c;
		c=[self _lookAhead0];
		NSLog(@"consumed %@ (%@) (%@)\n", c, [c matchString], [c astdef]);
		[self addAstNode:c astDef:[c astdef]];
	}
	tindex++;
}

- (void) _nomatch:(DBParserRule *)r
{
	NSAssert(0, @"parse error");
}


- (void) _triggerAction:(SEL) act
{
	if (!act) return;
	if (!target) return;
	DBLexerTokenMatch *t=[self _lookAhead0];
	[target performSelector:act withObject:t];
}

- (void) setTarget:(id)t
{
	[target release];
	target=[t retain];
}
- (id) target
{
	return target;
}


// ast

- (void) setNodeClass:(Class)c
{
	nodeClass=c;
}

- (void) addAstNode:(DBLexerTokenMatch*)tok astDef:(NSString *)astDef
{
	DBParserAstNode *node=[nodeClass astNodeWithToken:tok];
	[node setToken:tok];
	if ([astDef hasSubString:@"$"]) {
		[node setLeaf:YES];
	}
	if ([astDef hasSubString:@"L"]) {
		if (curNode) {
			[node setLeft:curNode];
			[curNode release];
			curNode=[node retain];
		} else {
			NSLog(@"node has L, but no curnode\n");
		}
	} else if (curNode) {
		if ([curNode isLeaf]) {
			NSLog(@"have curnode, but it is leaf\n");
		} else {
			[curNode setRight:node];
		}
	} else {
		[curNode release];
		curNode=[node retain];;
	}
}

- (void) astPush
{
	if (curNode) {
		//NSLog(@"astPush %@\n", curNode);
		[nodeStack addObject:curNode];
		[curNode release];
		curNode=nil;
	} else {
		//NSLog(@"astPush null\n");
		[nodeStack addObject:[NSNull null]];
	}
}

- (void) astPop
{
	DBParserAstNode *l;
	if (![nodeStack count]) {
		NSLog(@"node stack underflow\n");
		return;
	}
	l=[[nodeStack lastObject]retain];
	[nodeStack removeLastObject];
	if ([l isKindOfClass:[NSNull class]]) {
		//NSLog(@"astPop null\n");
		return;
	}
	if (!curNode) {
		// NSLog(@"astPop poped <%@> in curnode\n", l);
		curNode=l;
		return;
	}
	if (![curNode isLeaf] && ![curNode left]) {
		// NSLog(@"astPop poped <%@> in curnode.left, curnode is %@\n", l, curNode);
		[curNode setLeft:l];
		[l release];
	} else if (![l isLeaf] && ![l right]) {
		// NSLog(@"astPop poped <%@> setting right with curnode %@\n", l, curNode);
		[l setRight:curNode];
		[curNode release];
		curNode=l;
	} else {
		NSLog(@"astPop: dont know what to do\n");
	}
}

- (DBParserAstNode *) ast
{
	return curNode;
}

- (void) reset
{
	[curNode release]; 
	curNode=nil;
	[nodeStack release];

	nodeStack=[[NSMutableArray arrayWithCapacity:10]retain];
	tindex=0;
	tnum=0;
	[tokens release];
	tokens=nil;
}
@end


